﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Xml.Linq;

namespace SharePointUtilitiesForDevelopers
{
    /// <summary>
    /// A domain class that represents a SharePoint CAML query order by clause.
    /// </summary>
    [ReadOnly(true)]
    public class SharePointQueryOrderByClause
    {
        #region Fields

        private readonly Dictionary<string, SharePointQueryOrderByExpression> _expressions = new Dictionary<string, SharePointQueryOrderByExpression>();

        #endregion Fields

        #region Properties

        /// <summary>
        /// Gets or sets the expressions.
        /// </summary>
        /// <value>The expressions.</value>
        [Description("The expressions in the orderby clause.")]
        public ReadOnlyCollection<SharePointQueryOrderByExpression> Expressions
        {
            get { return _expressions.Values.ToList().AsReadOnly(); }
        }

        #endregion Properties

        #region Methods

        /// <summary>
        /// Clears the expressions.
        /// </summary>
        public void ClearExpressions()
        {
            _expressions.Clear();
        }

        /// <summary>
        /// Adds the expression.
        /// </summary>
        /// <param name="expression">The expression.</param>
        public void AddExpression(SharePointQueryOrderByExpression expression)
        {
            _expressions[expression.FieldStaticName] = expression;
        }

        /// <summary>
        /// Adds the expression.
        /// </summary>
        /// <param name="fieldStaticName">The field static name.</param>
        public void AddExpression(string fieldStaticName)
        {
            AddExpression(new SharePointQueryOrderByExpression(fieldStaticName, true));
        }

        /// <summary>
        /// Adds the expression.
        /// </summary>
        /// <param name="fieldStaticName">The field static name.</param>
        /// <param name="sortAscending">The sort direction.</param>
        public void AddExpression(string fieldStaticName, bool sortAscending)
        {
            AddExpression(new SharePointQueryOrderByExpression(fieldStaticName, sortAscending));
        }

        /// <summary>
        /// Determines whether the specified field id is contained by one of the expressions.
        /// </summary>
        /// <param name="fieldStaticName">The field static name.</param>
        /// <returns>
        /// 	<c>true</c> if the specified field id is contained by one of the expressions; otherwise, <c>false</c>.
        /// </returns>
        public bool ContainsFieldId(string fieldStaticName)
        {
            if (string.IsNullOrEmpty(fieldStaticName))
            {
                return false;
            }

            return _expressions.ContainsKey(fieldStaticName);
        }

        #endregion Methods

    }

    /// <summary>
    /// Contains extensions methods for <see cref="SharePointQueryOrderByClause"/>.
    /// </summary>
    public static class SharePointQueryOrderByClauseExtensionMethods
    {
        /// <summary>
        /// Gets orderby XML definition from the clause.
        /// </summary>
        /// <param name="clause">The clause.</param>
        /// <returns>An <see cref="XElement"/> that represents the orderby clause.</returns>
        public static XElement ToXElement(this SharePointQueryOrderByClause clause)
        {
            XNamespace ns = string.Empty;
            var orderByElement = new XElement(ns + "OrderBy");

            if(clause != null)
            {
                foreach (var expression in clause.Expressions)
                {
                    var expressionElement = new XElement(ns + "FieldRef", new XAttribute("Name", expression.FieldStaticName));
                    orderByElement.Add(expressionElement);
                }
            }

            return orderByElement;
        }

        /// <summary>
        /// Gets a <see cref="SharePointQueryOrderByClause"/> from the orderby definition.
        /// </summary>
        /// <param name="orderByDefinition">The order by definition.</param>
        /// <returns>A <see cref="SharePointQueryOrderByClause"/> that represents the orderby definition.</returns>
        public static SharePointQueryOrderByClause ToSharePointQueryOrderByClause(this XElement orderByDefinition)
        {
            var clause = new SharePointQueryOrderByClause();

            if (orderByDefinition != null)
            {

                var fieldRefs =
                    orderByDefinition.Descendants().Where(
                        ele =>
                        string.Compare(ele.Name.LocalName, "FieldRef", StringComparison.InvariantCultureIgnoreCase) == 0);

                foreach (var fieldRef in fieldRefs)
                {
                    clause.AddExpression(SharePointXml.GetAttributeAsString(fieldRef, "Name"),
                                         SharePointXml.GetAttributeAsBoolean(fieldRef, "Ascending", true));
                }
            }

            return clause;
        }
    }
}
